package com.jzo2o.foundations.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.MultiMatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.util.ObjectBuilder;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.es.core.ElasticSearchTemplate;
import com.jzo2o.es.utils.SearchResponseUtils;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.enums.FoundationStatusEnum;
import com.jzo2o.foundations.mapper.RegionMapper;
import com.jzo2o.foundations.mapper.ServeCacheMapper;
import com.jzo2o.foundations.mapper.ServeMapper;
import com.jzo2o.foundations.model.domain.Region;
import com.jzo2o.foundations.model.domain.ServeAggregation;
import com.jzo2o.foundations.model.domain.ServeSync;
import com.jzo2o.foundations.model.dto.response.ServeCategoryResDTO;
import com.jzo2o.foundations.model.dto.response.ServeSimpleResDTO;
import com.jzo2o.foundations.model.dto.response.ServeTypeDTo;
import com.jzo2o.foundations.service.ServeCacheService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ServeCacheServiceImpl implements ServeCacheService {
    @Resource
    private ServeCacheMapper serveCacheMapper;
    @Resource
    private RegionMapper regionMapper;
    @Resource
    private ServeMapper serveMapper;
    @Resource
    private ElasticSearchTemplate elasticSearchTemplate;

    /**
     * 服务分类列表
     */
    @Cacheable(value = RedisConstants.CacheName.SERVE_TYPE, key = "#regionId",cacheManager = RedisConstants.CacheManager.ONE_DAY)
    @Override
    public List<ServeTypeDTo> serveTypeList(Long regionId) {
        if(regionId != null){
            return serveCacheMapper.serveTypeList(regionId);
        }
       return null;
    }

    /**
     * 首页热门服务列表
     */
    @Cacheable(value = RedisConstants.CacheName.HOT_SERVE, key = "#regionId",cacheManager = RedisConstants.CacheManager.ONE_DAY)
    @Override
    public List<ServeSync> hotServeList(Long regionId) {
        if(regionId != null){
            return serveCacheMapper.hotServeList(regionId);
        }
        return null;
    }

    /**
     * 根据id查询服务
     */
    @Override
    public ServeSync getId(Long id) {
        if(id != null){
            return serveCacheMapper.getId(id);
        }
        return null;
    }

    /**
     * 首页服务列表
     */
    @Caching(cacheable = {
            //返回数据为空，则缓存空值30分钟，这样可以避免缓存穿透
            @Cacheable(value = RedisConstants.CacheName.SERVE_ICON,key ="#regionId" ,
                    unless ="#result.size()>0",cacheManager = RedisConstants.CacheManager.THIRTY_MINUTES),
            //返回值不为空，则永久缓存数据
            @Cacheable(value = RedisConstants.CacheName.SERVE_ICON,key ="#regionId" ,
                    unless ="#result.size()==0",cacheManager = RedisConstants.CacheManager.FOREVER)
    })
    @Override
    public  List<ServeCategoryResDTO> firstPageServeList(Long regionId) {
        //1、检查当前区域是否启用
        Region region = regionMapper.selectById(regionId);
        if(ObjectUtil.isEmpty(region) || ObjectUtil.notEqual(region.getActiveStatus(),FoundationStatusEnum.ENABLE.getStatus())){
            return Collections.emptyList();
        }
        //2、首页服务列表查询
        List<ServeCategoryResDTO> list = serveMapper.findServeIconCategoryByRegionId(regionId);
        if(CollUtil.isEmpty(list)){
            return Collections.emptyList();
        }

        //3、提取前2个服务类型
        list=list.subList(0,(Math.min(list.size(), 2)));
        list = new ArrayList<>(list);

        //4、提取每个类型的前4个服务列表
        list.forEach(v->{
            List<ServeSimpleResDTO> serveList = v.getServeResDTOList();
            serveList=serveList.subList(0, Math.min(serveList.size(), 4));
            serveList = new ArrayList<>(serveList);
            v.setServeResDTOList(serveList);
        });
        return list;
    }

    /**
     * 服务搜索
     */
    @Override
    public List<ServeSimpleResDTO> findServeList(String cityCode, Long serveTypeId, String keyword) {
        // 构造查询条件
        //SearchRequest.Builder builder = new SearchRequest.Builder();
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.query(query->query.bool(bool->{
            //匹配 citycode
            bool.must(must->
                    must.term(term->
                            term.field("city_code").value(cityCode)));
            // 匹配服务类型
            if (ObjectUtil.isNotEmpty(serveTypeId)) {
            bool.must(new Function<Query.Builder, ObjectBuilder<Query>>() {
                @Override
                public ObjectBuilder<Query> apply(Query.Builder builder) {
                    return builder.multiMatch(new Function<MultiMatchQuery.Builder, ObjectBuilder<MultiMatchQuery>>() {
                        @Override
                        public ObjectBuilder<MultiMatchQuery> apply(MultiMatchQuery.Builder builder) {
                            return builder.fields("serve_type_id").query(serveTypeId.toString());
                        }
                    });
                }
            });
            }
            //匹配关键字
            if(ObjectUtils.isNotEmpty(keyword)){
                bool.must(must->
                        must.multiMatch(multiMatch->
                                multiMatch.fields("serve_item_name","serve_type_name").query(keyword)));
            }
            return bool;
        }));
        // 排序 按服务项的serveItemSortNum排序(升序)
        List<SortOptions> sortOptions = new ArrayList<>();
        sortOptions.add(SortOptions.of(sortOption -> sortOption.field(field->field.field("serve_item_sort_num").order(SortOrder.Asc))));
        builder.sort(sortOptions);
        //指定索引
        builder.index("serve_aggregation");
        //请求对象
        SearchRequest searchRequest = builder.build();
        // 检索数据
        SearchResponse<ServeAggregation> searchResponse = elasticSearchTemplate.opsForDoc().search(searchRequest, ServeAggregation.class);
        //如果搜索成功返回结果集
        if (SearchResponseUtils.isSuccess(searchResponse)) {
            List<ServeAggregation> collect = searchResponse.hits().hits()
                    .stream().map(hit -> {
                        ServeAggregation serve = hit.source();
                        return serve;
                    })
                    .collect(Collectors.toList());
            List<ServeSimpleResDTO> serveSimpleResDTOS = BeanUtil.copyToList(collect, ServeSimpleResDTO.class);
            return serveSimpleResDTOS;
        }
        return  Collections.emptyList();

    }

}
